一個好的工程師,就是有好的除錯能力,有效率的除錯方式,就是在執行程式時,出錯時能回報有效的錯誤訊息,因此錯誤處理是一件非常重要的事。這裡我事先聲明,大部分都是參照 參考來源1 的寫法,因為覺得講得很不錯,就用這篇內容作為例子講解,如果有版權問題的話,請提醒我!
產生錯誤訊息的方式就是 errors.New(),如下所示:
err := errors.New("建立錯誤訊息")
由於 error 在 go 中的定義是一個 interface,透過 day06 的概念,表示我們也可以製作自己的錯誤訊息
type error interface {
Error() string
}
製作自定義的錯誤訊息,常見寫法如下:
// STEP 1:定義客製化的 error struct
type MyError struct {
Time time.Time
Message string
}
// STEP 2:定義能夠屬於 Error Interface 的方法
func (e *MyError) Error() string {
return fmt.Sprintf("喔耶,已經%v了,%s", e.Time.Format("15:04:05"), e.Message)
}
// STEP 3:拋出錯誤的函式
func errHandler(status bool) (error, bool) {
if status {
return nil, true
}
return &MyError{
Time: time.Now(),
Message: "我要來耍廢了",
}, false
}
// STEP 4:使用 fmt.Println 即可取得錯誤拋出的訊息
func main() {
result := run(errHandler)
result(true)
result(false)
}
// PS 只是讓程式碼比較好看的改寫,不一定需要
func run(op func(status bool) (error, bool)) func(bool) {
return func(status bool) {
if err, ok := op(status); ok {
fmt.Println("ok")
} else {
fmt.Println(err)
}
}
}
輸出結果為:
ok
喔耶,已經22:22:22了,我要來耍廢了
但是有時候我們可能會遇到更多情況,比方說我們想給使用者看到的訊息與伺服器 log 的錯誤訊息不同,那麼我們該怎麼做?以上面的例子為例,這時候我們就可以使用 err.(MyError) 來看看是不是我們定義的錯誤類別,所以表示我們可以創建多種不同的錯誤 struct,然後用同樣的邏輯來判斷屬於什麼類型 struct 的錯誤訊息,以下為例:
判斷 error 型態的寫法:
errorStruct, isErrorStruct := err.(ErrorStruct)
實際操作:
// // 情境1: 簡易的 error handling
// // STEP 1:定義客製化的 error struct
// type MyError struct {
// Time time.Time
// Message string
// }
type YourError struct {
Time time.Time
Message string
}
// // STEP 2:定義能夠屬於 Error Interface 的方法
// func (e *MyError) Error() string {
// return fmt.Sprintf("喔耶,已經%v了,%s", e.Time.Format("15:04:05"), e.Message)
// }
func (e *YourError) Error() string {
return fmt.Sprintf("已經%v了,%s", e.Time.Format("15:04:05"), e.Message)
}
// // STEP 3:拋出錯誤的函式
// func errHandler(status bool) (error, bool) {
// if status {
// return nil, true
// }
// return &MyError{
// Time: time.Now(),
// Message: "我要來耍廢了",
// }, false
// }
func yourErrHandler(status bool) (error, bool) {
if status {
return nil, true
}
return &YourError{
Time: time.Now(),
Message: "換你耍廢了",
}, false
}
// STEP 4:使用 fmt.Println 即可取得錯誤拋出的訊息
func main() {
// result := run(errHandler)
// result(true)
// result(false)
isMyError(errHandler)
isMyError(yourErrHandler)
}
// PS 只是讓程式碼比較好看的改寫,不一定需要
type errType func(bool) (error, bool)
// // PS 只是讓程式碼比較好看的改寫,不一定需要
// func run(op errType) func(bool) {
// return func(status bool) {
// if err, ok := op(status); ok {
// fmt.Println("ok")
// } else {
// fmt.Println(err)
// }
// }
// }
func isMyError(op errType) {
err, _ := op(false)
if err != nil {
switch err.(type) {
case *MyError:
fmt.Println("MyError: ", err)
case *YourError:
fmt.Println("YourError: ", err)
default:
fmt.Println("沒有定義是誰的錯")
}
}
}
https://github.com/luckyuho/ithome30-golang/tree/main/day08